package sim

import (
	"context"
	"go.uber.org/zap"
	carpb "serve/car/api/gen/v1"
	"serve/car/mq"
	"time"
)

type Controller struct {
	CarService carpb.CarServiceClient
	Logger     *zap.Logger
	Subscriber mq.Subscriber
}

func (c *Controller) RunSimulations(ctx context.Context) {
	var cars []*carpb.CarEntity

	for {
		time.Sleep(3 * time.Second)
		res, err := c.CarService.GetCars(ctx, &carpb.GetCarsRequest{})
		if err != nil {
			c.Logger.Error("获取所有汽车失败", zap.Error(err))
			continue
		}
		cars = res.Cars
		break
	}

	c.Logger.Info("获取到汽车", zap.Int("count", len(cars)))

	msgCh, cleanUP, err := c.Subscriber.Subscribe(ctx) // 这里创建接收消息的连接
	defer cleanUP()

	if err != nil {
		c.Logger.Error("接收消息失败", zap.Error(err))
		return
	}

	carChan := make(map[string]chan *carpb.Car) // 创建carid 和chan的关系对应

	for _, car := range cars { // 循环每辆车
		ch := make(chan *carpb.Car)
		carChan[car.Id] = ch

		go c.SimulateCar(context.Background(), car, ch) // 开启协查
	}

	for carUpdate := range msgCh { // 接收消息
		ch := carChan[carUpdate.Id] // 收到的消息id和chan绑定
		if ch != nil {              // 如果ch不为亏
			ch <- carUpdate.Car // 发送消息到协查
		}
	}
}

func (c *Controller) SimulateCar(ctx context.Context, initial *carpb.CarEntity, ch chan *carpb.Car) {
	carID := initial.Id
	c.Logger.Info("模拟汽车:", zap.String("id", carID))

	for update := range ch {
		c.Logger.Info("汽车收到消息", zap.String("id", carID), zap.String("status", transformationCatStatus(update.Status)))

		if update.Status == carpb.CarStatus_UNLOCKING { // 开锁
			_, err := c.CarService.UpdateCar(ctx, &carpb.UpdateCarRequest{
				Id:     carID,
				Status: carpb.CarStatus_UNLOCKED,
				Pos:    nil,
			})
			if err != nil {
				c.Logger.Error("开锁失败", zap.String("carid", carID), zap.Error(err))
			}
			c.Logger.Info("开锁成功", zap.String("carid", carID))

		} else if update.Status == carpb.CarStatus_LOCKING {
			_, err := c.CarService.UpdateCar(ctx, &carpb.UpdateCarRequest{
				Id:     carID,
				Status: carpb.CarStatus_LOCKED,
				Pos:    nil,
			})
			if err != nil {
				c.Logger.Error("关锁失败", zap.String("carid", carID), zap.Error(err))
			}
			c.Logger.Info("关锁成功", zap.String("carid", carID))
		}
	}
}

func transformationCatStatus(status carpb.CarStatus) string {
	switch status {
	case carpb.CarStatus_CS_NOT_SPECIFIED:
		return "初始状态"
	case carpb.CarStatus_LOCKED:
		return "锁上"
	case carpb.CarStatus_UNLOCKING:
		return "开锁中"
	case carpb.CarStatus_UNLOCKED:
		return "开锁"
	case carpb.CarStatus_LOCKING:
		return "上锁中"
	}
	return ""
}
